#

| Chapter 11 The Lessons of History |

## 11.7 History Substitutions

[Although most of the examples here use echo to demonstrate clearly just what is going on, you'll normally use history with other UNIX commands. -JP]

The exclamation point (`!`) is the C shell's default (11.15) history substitution character. (It's used in bash, too.) This allows you to recall previously entered commands and re-execute them without retyping. The number of commands saved is up to you. To set this number, put a line in your shell setup file (2.2) like this:

>     set history=40   ...C shell

>     HISTSIZE=40   ...bash, ksh

This means that the C shell will save the last 40 commands. To list out these 40 commands use:

>     % history

To see just the last ten commands in csh or bash, use `history 10`. In the C shell, you can also list out the commands in reverse with `history -r`.

To use the `!` in a command line, you have several choices. Some of the following examples are more of a headache than they may be worth. But they are used mostly to select arguments from the command line in aliases (10.3). Here they are:

- `!!` repeats the last command.

- `!:` repeats the last command. This form is used if you want to add a modifier (9.6) like:

  >     % echo xy
  >     xy
  >     % !:s/xy/yx
  >     echo yx
  >     yx

  The second `!` was left out.

- `!so` repeats the last command that starts with `so`.

- `!?fn?` repeats the last command that has `fn` anywhere in it. The string could be found in an argument or in the command name. This is opposed to `!fn`, in which `!fn` must be in a command name. (The last `?` need not be there. Thus `!?fn` means the same thing.)

- `!34` executes command number 34. You can find the appropriate history number when you list your history using the history command, or by putting the history number in your prompt . (7.2)

- `!! &` adds an ampersand (`&`) to the end of the last command, which executes it and places it into the background. You can add anything to the end of a previous command. For example:

  >     % cat -v foo
  >            ...
  >     % !! | more
  >     cat -v foo | more
  >            ...

  In this case the shell will repeat the command to be executed and run it, adding the pipe through the more (25.3) pager. Another common usage is:

  >     % cat -v foo
  >            ...
  >     % !! > out
  >     cat -v foo > out

  which returns the command but redirects the output into a file.

- `!:0` selects only the command name; rather than the entire command line.

  >     % /usr/bin/grep Ah fn1
  >            ...
  >     % !:0 Bh fn2
  >     /usr/bin/grep Bh fn2

  Note that as an operator (9.6) `:0` can be appended to these history substitutions as well. For example, `!!:0` will give the last command name, and a colon followed by any number will give the corresponding argument. For example:

  >     % cat fn fn1 fn2
  >            ...
  >     % more !:3
  >     more fn2
  >            ...

  gives the third argument.

- `!:2-4` gives the second through the fourth argument, or any numbers you choose:

  >     % echo 1 2 3 4 5
  >     1 2 3 4 5
  >     % echo !:2-4
  >     echo 2 3 4
  >     2 3 4

- `!:-3` gives zero through the third argument, or any number you wish:

  >     % echo 1 2 3 4
  >     1 2 3 4
  >     % echo !:-3
  >     echo echo 1 2 3
  >     echo 1 2 3

- `!^` gives the first argument of the previous command. This is the same as `!:1`. Remember that, just as the `^` (caret) is the beginning-of-line anchor in regular expressions (26.4), `!^` gives the beginning history argument.

  >     % cat fn fn1 fn2
  >            ...
  >     % more !^
  >     more fn
  >            ...

- `!$` gives the last argument of the last command. In the same way that `$` (dollar sign) is the end-of-line anchor in regular expressions, `!$` gives the ending history argument. Thus:

  >     % cat fn
  >            ...
  >     % more !$
  >     more fn
  >            ...

  The new command (`more`) is given the last argument of the previous command.

- `!*` is shorthand for the first through the last argument. This is used a lot in aliases:

  >     % echo 1 2 3 4 5
  >     1 2 3 4 5
  >     % echo !*
  >     echo 1 2 3 4 5
  >     1 2 3 4 5

  In an alias:

  >     alias vcat 'cat -v \!* | more'

  will pipe the output of cat -v (25.7) command through more. The backslash (`\`) has to be there to hide the history character, `!`, until the alias is used-see article 10.3 for more information.

- `!:2*` gives the second through the last arguments:

  >     % echo 1 2 3 4 5
  >     1 2 3 4 5
  >     % echo !:2*
  >     echo 2 3 4 5
  >     2 3 4 5

- `!:2-` like `2*` but the last argument is dropped:

  >     % echo 1 2 3 4 5
  >     1 2 3 4 5
  >     % echo !:2-
  >     echo 2 3 4
  >     2 3 4

- `!?fn?%` gives the first word found that has `fn` in it:

  >     % sort fn1 fn2 fn3
  >            ...
  >     % echo !?fn?%
  >     echo fn1
  >     fn1

  That found the `fn` in `fn1`. You can get wilder with:

  >     % echo 1 2 3 4 5
  >     1 2 3 4 5
  >     % echo !?ec?^
  >     echo 1
  >     1

  That selected the command that had `ec` in it, and the caret (`^`) said to give the first argument of that command. You can also do something like:

  >     % echo fn fn1 fn2
  >     fn fn1 fn2

  >     % echo !?fn1?^ !$
  >     echo fn fn2
  >     fn fn2

  That cryptic command told the shell to look for a command that had `fn1` in it (`!?fn1?`), and gave the first argument of that command (`^`). Then it gave the last argument (`!$`).

- `^xy^yx` is the shorthand substitution (11.3, 11.5) command. In the case of:

  >     % echo xxyyzzxx
  >     xxyyzzxx
  >     % ^xx^ab
  >     echo abyyzzxx
  >     abyyzzxx

  it replaced the characters `xx` with `ab`. This makes editing the previous command much easier.

- `!!:s/xx/ab/` is doing the same thing as the previous example, but it is using the substitute command instead of the `^`. This works for any previous command, as in:

  >     % more afile bfile
  >            ...
  >     % echo xy
  >     xy
  >     % !m:s/b/c/
  >     more afile cfile

  You do not have to use the slashes (`/`); any character can act as a delimiter.

  >     % !!:s:xy:yx

  There we used the colons (`:`) [good when the word you're trying to edit contains a slash-JP ]. If you want to add more to the replacement, use `&` to "replay it" and then add on whatever you like:

  >     % echo xy
  >     xy
  >     % !!:s/xy/&yx
  >     echo xyyx
  >     xyyx

  The `&` in the replacement part said to give what the search part found, which was the `xy` characters.

  The search part, or left side, cannot include metacharacters (26.3). You must type the actual string you are looking for.

  Also, the example above only replaces the first occurrence of `xy`. To replace them all, use g:

  >     % echo xy xy xy xy
  >     xy xy xy xy
  >     % !!:s/xy/yx/
  >     echo yx xy xy xy
  >     yx xy xy xy
  >     % !!:gs/xy/yx/
  >     echo yx yx yx yx
  >     yx yx yx yx

  The g command in this case meant do all the `xy`s. And oddly enough, the g has to come before the s command.

  Or you could have done:

  >     % echo xy xy xy xy
  >     xy xy xy xy
  >     % !!:s/xy/yx/
  >     echo yx xy xy xy
  >     yx xy xy xy
  >     % !!:g&
  >     echo yx yx yx yx
  >     yx yx yx yx

  In that case, we told the shell to globally (`:g`) replace every matched string from the last command with the last substitution (`&`). Without the g command, the shells would have replaced just one more `xy` with `yx`.

  [A "global" substitution works just once per word:

  >     % echo xyzzy
  >     xyzzy
  >     % !!:gs/y/p/
  >     echo xpzzy
  >     xpzzy

  The substitution above changed only the first `y`. -TC ]

- DR

11.6 Using !$ for Safety with Wildcards |  | 11.8 Repeating a Cycle of Commands